iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Rust

30天Rust從零到全端系列 第 6

Day 6: 迴圈進階與迭代器

  • 分享至 

  • xImage
  •  

前言

Hi 大家,今天我們來看看 Rust 的迭代器系統。

迭代器基礎

創建迭代器

fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    
    // 三種迭代方式
    
    // 1. iter() - 借用引用
    for item in vec.iter() {
        println!("借用: {}", item); // item 是 &i32
    }
    
    // 2. into_iter() - 取得所有權
    let vec2 = vec![1, 2, 3];
    for item in vec2.into_iter() {
        println!("擁有: {}", item); // item 是 i32
    }
    // vec2 在這裡已經無法使用
    
    // 3. iter_mut() - 可變借用
    let mut vec3 = vec![1, 2, 3];
    for item in vec3.iter_mut() {
        *item *= 2; // 修改原始值
    }
    println!("修改後: {:?}", vec3);
}

迭代器適配器

fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 鏈式操作
    let result: Vec<i32> = numbers
        .iter()
        .filter(|&&x| x % 2 == 0)    // 過濾偶數
        .map(|&x| x * x)             // 平方
        .filter(|&x| x > 10)         // 大於 10
        .collect();                  // 收集結果
    
    println!("處理結果: {:?}", result);
    
    // 更複雜的操作
    let text_numbers = numbers
        .iter()
        .take(5)                     // 取前 5 個
        .skip(2)                     // 跳過前 2 個
        .enumerate()                 // 加上索引
        .map(|(i, &x)| format!("第{}個: {}", i, x))
        .collect::<Vec<String>>();
    
    for text in text_numbers {
        println!("{}", text);
    }
}

消費適配器

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // reduce 操作
    let sum: i32 = numbers.iter().sum();
    let product: i32 = numbers.iter().product();
    
    println!("總和: {}", sum);
    println!("乘積: {}", product);
    
    // find 操作
    let found = numbers.iter().find(|&&x| x > 3);
    match found {
        Some(value) => println!("找到大於 3 的數: {}", value),
        None => println!("沒有找到"),
    }
    
    // any 和 all
    let has_even = numbers.iter().any(|&x| x % 2 == 0);
    let all_positive = numbers.iter().all(|&x| x > 0);
    
    println!("有偶數: {}", has_even);
    println!("全部正數: {}", all_positive);
    
    // fold 和 reduce
    let sum_fold = numbers.iter().fold(0, |acc, &x| acc + x);
    let sum_reduce = numbers.iter().cloned().reduce(|acc, x| acc + x);
    
    println!("fold 總和: {}", sum_fold);
    println!("reduce 總和: {:?}", sum_reduce);
}

自定義迭代器

實作 Iterator trait

struct Counter {
    current: usize,
    max: usize,
}

impl Counter {
    fn new(max: usize) -> Counter {
        Counter { current: 0, max }
    }
}

impl Iterator for Counter {
    type Item = usize;
    
    fn next(&mut self) -> Option<Self::Item> {
        if self.current < self.max {
            let current = self.current;
            self.current += 1;
            Some(current)
        } else {
            None
        }
    }
}

fn main() {
    let counter = Counter::new(5);
    
    for num in counter {
        println!("計數: {}", num);
    }
    
    // 使用自定義迭代器的適配器
    let sum: usize = Counter::new(5)
        .filter(|&x| x % 2 == 0)
        .map(|x| x * x)
        .sum();
    
    println!("偶數平方和: {}", sum);
}

實際專案:日誌分析器

use std::io;
use std::collections::HashMap;

#[derive(Debug, Clone)]
struct LogEntry {
    timestamp: String,
    level: String,
    message: String,
}

impl LogEntry {
    fn new(line: &str) -> Option<LogEntry> {
        let parts: Vec<&str> = line.splitn(3, ' ').collect();
        if parts.len() == 3 {
            Some(LogEntry {
                timestamp: parts[0].to_string(),
                level: parts[1].to_string(),
                message: parts[2].to_string(),
            })
        } else {
            None
        }
    }
}

fn main() {
    println!("=== 日誌分析器 ===");
    
    let sample_logs = vec![
        "2024-01-01T10:00:00 INFO 系統啟動成功",
        "2024-01-01T10:05:00 WARN 記憶體使用率較高",
        "2024-01-01T10:10:00 ERROR 資料庫連線失敗",
        "2024-01-01T10:15:00 INFO 使用者登入: user123",
        "2024-01-01T10:20:00 ERROR 檔案讀取錯誤",
        "2024-01-01T10:25:00 INFO 系統備份完成",
    ];
    
    let logs: Vec<LogEntry> = sample_logs
        .iter()
        .filter_map(|&line| LogEntry::new(line))
        .collect();
    
    loop {
        println!("\n選擇分析方式:");
        println!("1. 依等級統計");
        println!("2. 顯示錯誤日誌");
        println!("3. 搜尋關鍵字");
        println!("4. 離開");
        
        match get_choice() {
            1 => analyze_by_level(&logs),
            2 => show_errors(&logs),
            3 => search_logs(&logs),
            4 => break,
            _ => println!("無效選擇"),
        }
    }
}

fn get_choice() -> i32 {
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap_or(0);
    input.trim().parse().unwrap_or(0)
}

fn analyze_by_level(logs: &Vec<LogEntry>) {
    let level_counts = logs
        .iter()
        .fold(HashMap::new(), |mut acc, log| {
            *acc.entry(log.level.clone()).or_insert(0) += 1;
            acc
        });
    
    println!("\n=== 等級統計 ===");
    for (level, count) in level_counts {
        println!("{}: {} 筆", level, count);
    }
}

fn show_errors(logs: &Vec<LogEntry>) {
    println!("\n=== 錯誤日誌 ===");
    
    logs.iter()
        .filter(|log| log.level == "ERROR")
        .enumerate()
        .for_each(|(i, log)| {
            println!("{}. [{}] {}", i + 1, log.timestamp, log.message);
        });
}

fn search_logs(logs: &Vec<LogEntry>) {
    println!("請輸入搜尋關鍵字:");
    let mut keyword = String::new();
    io::stdin().read_line(&mut keyword).expect("讀取失敗");
    let keyword = keyword.trim();
    
    let matching_logs: Vec<&LogEntry> = logs
        .iter()
        .filter(|log| log.message.contains(keyword))
        .collect();
    
    println!("\n=== 搜尋結果: '{}' ===", keyword);
    
    if matching_logs.is_empty() {
        println!("未找到相關日誌");
    } else {
        for (i, log) in matching_logs.iter().enumerate() {
            println!("{}. [{}] [{}] {}", 
                i + 1, log.timestamp, log.level, log.message);
        }
    }
}

總結

今天我們掌握了:

  • 迭代器的三種創建方式
  • 迭代器適配器的鏈式操作
  • 消費適配器的各種用法
  • 自定義迭代器的實作
  • 在實際專案中運用迭代器

上一篇
Day 5: 控制流程進階與錯誤處理
下一篇
Day 7: 第一個完整專案 - 終端機任務管理器
系列文
30天Rust從零到全端15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言